package com.tyut.musicdreamer.service.gateway.config;

import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 网关认证配置
 */
@Configuration
@Slf4j
public class GatewayAuthConfig {

    /**
     * 注册Sa-Token全局过滤器
     */
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        return new SaReactorFilter()
                // 指定拦截路由
                .addInclude("/**")
                // 排除不需要拦截的路由
                .addExclude(
                        "/health",
                        "/api/auth/login",
                        "/api/auth/register",
                        "/api/auth/captcha",
                        "/api/music/list",
                        "/api/music/search",
                        "/api/music/*/stream",
                        "/api/music/*/cover",
                        "/api/music/*/url",
                        "/api/music/*/download",
                        "/api/music/detail/*"
                )
                // 认证函数: 每次请求执行
                .setAuth(obj -> {
                    // 记录当前请求路径
                    final String[] pathRef = {("未知路径")};
                    
                    // 获取ServerWebExchange对象
                    if (obj instanceof ServerWebExchange) {
                        ServerWebExchange exchange = (ServerWebExchange) obj;
                        if (exchange.getRequest() != null) {
                            pathRef[0] = exchange.getRequest().getPath().toString();
                            log.debug("处理认证请求: {}", pathRef[0]);
                        }
                    }
                    
                    // 公开接口，无需登录
                    SaRouter.match("/api/auth/login", "/api/auth/register", "/api/auth/captcha").stop();
                    SaRouter.match("/health").stop();
                    SaRouter.match("/api/music/list", "/api/music/search").stop();
                    SaRouter.match("/api/music/*/stream", "/api/music/*/cover", "/api/music/*/url", "/api/music/*/download").stop();
                    SaRouter.match("/api/music/detail/*").stop();
                    
                    // 其他API需要登录
                    SaRouter.match("/api/**").check(r -> {
                        // 检查是否登录
                        boolean isLogin = StpUtil.isLogin();
                        log.debug("检查登录状态: path={}, isLogin={}", pathRef[0], isLogin);
                        
                        if (isLogin) {
                            // 记录当前登录用户ID
                            Object loginId = StpUtil.getLoginIdDefaultNull();
                            log.debug("当前登录用户: {}", loginId);
                        } else {
                            log.warn("未登录用户访问需要认证的接口: {}", pathRef[0]);
                        }
                        
                        StpUtil.checkLogin();
                    });
                    
                    // 管理员接口需要角色校验
                    SaRouter.match("/api/admin/**", r -> {
                        boolean hasRole = StpUtil.hasRole("admin");
                        log.debug("检查管理员角色: path={}, hasRole={}", pathRef[0], hasRole);
                        StpUtil.checkRole("admin");
                    });
                })
                // 异常处理函数：处理认证异常
                .setError(e -> {
                    log.error("认证异常: {}", e.getMessage());
                    
                    // 返回统一格式的错误信息，状态码由框架自动设置为401
                    String json = "{\"code\":401,\"message\":\"认证失败，请重新登录\"}";
                    return Mono.just(json);
                });
    }
} 